//定义一个全局变量保存watcher信息
let W = null
class Watcher {
    //接收两个参数:key所在的对象 和key
    constructor(obj, key) {
        this.obj = obj
        this.key = key
        //每次访问值时保存当前watcher到全局
        W = this
        this.get()
        //每次访问结束将W值初始
        W = null
    }
    //访问对象
    get() {
        return this.obj[this.key]
    }
    //更新时重新获取数据
    update() {
        console.log(
            "gogogo,有人通知我了,我重新去请求数据是:" +
            this.get() +
            ",然后开始重新渲染视图!!!!"
            );
    }
}

//封装一个Dep类,用来收集所有访问的watcher的信息,发布时通知更新
class Dep {
    constructor() {
        //在实例上放一个空数组,收集所有的依赖
        this.subs = []
    }
    depend(watcher) {
        //每次访问数据时,将watcher放入数组中
        this.subs.push(watcher)
    }
    notify() {
        // 每次数据更新时通知所有watcher更新
        this.subs.forEach(watcher => {
            watcher.update();
        })
    }
}



//封装一个Observe类,主要用来处理发布订阅模式的核心操作(响应式操作:  收集依赖,通知更新)
class Observe {
    constructor(obj) {
        this.obj = obj

        //深层次数据劫持时,经过判断_data内的值是否为数组
        if (Array.isArray(obj)) {
            // 如果是数组则遍历继续判断数组内的值是否为数组
            return this.observeArray(obj)
        } else {
            this.walk(obj)
        }
    }

    observeArray(obj) {
        obj.forEach(item => {
            observer(item)
        })
    }

    walk(obj) {
        for (const key of Object.keys(obj)) {
            //将每个数据响应式的核心代码交给defineReactive处理
            defineReactive(obj, key, obj[key])
        }
    }

}

//封装defineReactive函数，主要是为了对单个数据做数据劫持（数据劫持的核心代码）
function defineReactive(obj, key, value) {
    //判断obj的每一个值进行深层次的数据劫持
    observer(value)

    //每个值数据劫持获取访问者信息
    const dep = new Dep()

    Object.defineProperty(obj, key, {
        get() {
            //当这个数据被请求的时候,把观察者watcher收集起来到dep.subs中
            //我们可能不在模板解析的时候(也就是不是Watcher来要数据),我们需要做判断处理
            if (W) {
                console.log('收集所有watcher的信息');
                dep.depend(W)
            }

            return value
        },
        set(newVal) {
            value = newVal

            console.log('数据更新,通知watcher重新获取值');
            dep.notify()
        },
    })
}



//定义一个observer函数 将对象内的所有属性一个个添加数据劫持
function observer(obj) {
    //深层次数据劫持时,判断_data内的属性值是否为基本类型
    if (typeof obj !== 'object' || obj === null) return

    new Observe(obj)

}

function Vue(options) {
    //将配置项放在Vue实例上
    this._data = options.data

    //数据代理,将this._data 的值放在this上,直接访问this.name时通过存取器属性实际上是读取,修改this._data的值
    for (let key of Object.keys(this._data)) {

        Object.defineProperty(this, key, {
            get() {
                return this._data[key]
            },
            set(value) {
                this._data[key] = value
            }
        })
    }
    observer(this._data)
}

//实例化Vue,传入配置项
const vm = new Vue({
    data: {
        name: 'laowang',
        age: 19,
        hobby: [{
                id: '001',
                cont: '抽烟'
            },
            {
                id: '002',
                cont: '喝酒'
            },
            {
                id: '003',
                cont: '烫头'
            }
        ]
    }
})




// console.log(vm);

function get() {
    console.log(new Watcher(vm._data.hobby[0], "cont"));
}

function set() {
    vm._data.hobby[0].cont=2
}


get()
set()